package edu.hawaii.myisern.action;

import java.math.BigInteger;
import java.util.Iterator;
import java.util.List;
import javax.xml.bind.JAXBException;
import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.Resolution;
import org.xml.sax.SAXException;
import edu.hawaii.myisern.collaborations.jaxb.CollaboratingOrganizations;
import edu.hawaii.myisern.collaborations.jaxb.Collaboration;
import edu.hawaii.myisern.collaborations.jaxb.CollaborationTypes;
import edu.hawaii.myisern.collaborations.jaxb.OutcomeTypes;
import edu.hawaii.myisern.collaborations.jaxb.Years;
import edu.hawaii.myisern.model.MyIsernModel;
import edu.hawaii.myisern.xmldatabase.XmlLoader;

/**
 * ActionBean for Collaboration, both listing and editing.
 * 
 * @author Shaoxuan Zhang
 * @author Laura Matsuo
 *
 */
public class CollaborationActionBean extends MyIsernActionBean {
  /** MyIsern instance manipulated by all webapp users. */
  private MyIsernModel myIsern = MyIsernModel.getInstance();;
  /** Our single organization instance manipulated by all webapp users. */
  private Collaboration collaboration = new Collaboration();
  private String message = "";
  private String collaboratingOrganizations = null;
  private String collaborationTypes = null;
  private String outcomeTypes = null;
  private String years = null;

  /**
   * Constructor
   * 
   * @throws JAXBException when JAXB fails.
   * @throws SAXException when SAX fails.
   */
  public CollaborationActionBean() throws JAXBException, SAXException {
    // empty constructor
  }

  /**
   * Gets the message to display to the user, such as when a collaboration has been added.
   * 
   * @return The message to display to the user.
   */
  public String getMessage() {
    return this.message;
  }

  /**
   * Sets the message to display to the user, such as when a collaboration has been added. 
   * @param message The message to display to the user.
   */
  public void setMessage(String message) {
    this.message = message;
  }
  
  /**
   * Return the name of this organization.
   * 
   * @return - a String
   */
  public String getName() {
    return this.collaboration.getName();
  }
  
  /**
   * Sets the name of this organization.
   * @param name the name of this organization
   */
  public void setName(String name) {
    this.collaboration.setName(name);
  }
  
  
  /**
   * Return the Description of this Collaboration.
   * 
   * @return - a String
   */
  public String getDescription() {
    return this.collaboration.getDescription();
  }

  /**
   * Set the Description.
   * 
   * @param value - String of given value.
   */
  public void setDescription(String value) {
    this.collaboration.setDescription(value);
  }
  
  /**
   * Return the Iterator of List that contains names of Collaborating Organizations
   * @return an Interator of String
   */
  public Iterator<String> getCollaboratingOrganizationsIterator() {
    return this.collaboration.getCollaboratingOrganizations().getCollaboratingOrganization()
        .iterator();
  }

  /**
   * Get a String that represents Collaborating Organizations.
   * 
   * @return a String that contain several names, separated by "\n".
   */
  public String getCollaboratingOrganizations() {
    if (this.collaboratingOrganizations == null) {
      this.collaboratingOrganizations = XmlLoader.joinListToString(this.collaboration
          .getCollaboratingOrganizations().getCollaboratingOrganization(), "\n");
    }
    return this.collaboratingOrganizations;
  }

  /**
   * Set a String that represents Collaborating Organizations.
   * 
   * @param collaboratingOrganizations a String that contain several names, separated by "\n".
   */
  public void setCollaboratingOrganizations(String collaboratingOrganizations) {
    this.collaboratingOrganizations = collaboratingOrganizations;
    this.collaboration.setCollaboratingOrganizations(new CollaboratingOrganizations());
    this.collaboration.getCollaboratingOrganizations().getCollaboratingOrganization().addAll(
        XmlLoader.splitStringToList(this.collaboratingOrganizations, "\n"));
  }

  /**
   * Return the Iterator of List that contains names of CollaborationTypes
   * @return an Interator of String
   */
  public Iterator<String> getCollaborationTypesIterator() {
    return this.collaboration.getCollaborationTypes().getCollaborationType().iterator();
  }

  /**
   * Get a String that represents CollaborationTypes.
   * 
   * @return a String that contain several names, separated by "\n".
   */
  public String getCollaborationTypes() {
    if (this.collaborationTypes == null) {
      this.collaborationTypes = XmlLoader.joinListToString(this.collaboration
          .getCollaborationTypes().getCollaborationType(), "\n");
    }
    return this.collaborationTypes;
  }

  /**
   * Set a String that represents CollaborationTypes.
   * 
   * @param collaborationTypes a String that contain several names, separated by "\n".
   */
  public void setCollaborationTypes(String collaborationTypes) {
    this.collaborationTypes = collaborationTypes;
    this.collaboration.setCollaborationTypes(new CollaborationTypes());
    this.collaboration.getCollaborationTypes().getCollaborationType().addAll(
        XmlLoader.splitStringToList(this.collaborationTypes, "\n"));
  }

  /**
   * Return the Iterator of List that contains names of OutcomeType
   * @return an Interator of String
   */
  public Iterator<String> getOutcomeTypesIterator() {
    return this.collaboration.getOutcomeTypes().getOutcomeType().iterator();
  }

  /**
   * Get a String that represents OutcomeTypes.
   * 
   * @return a String that contain several names, separated by "\n".
   */
  public String getOutcomeTypes() {
    if (this.outcomeTypes == null) {
      this.outcomeTypes = XmlLoader.joinListToString(this.collaboration.getOutcomeTypes()
          .getOutcomeType(), "\n");
    }
    return this.outcomeTypes;
  }

  /**
   * Set a String that represents OutcomeTypes.
   * 
   * @param outcomeTypes a String that contain several names, separated by "\n".
   */
  public void setOutcomeTypes(String outcomeTypes) {
    this.outcomeTypes = outcomeTypes;
    this.collaboration.setOutcomeTypes(new OutcomeTypes());
    this.collaboration.getOutcomeTypes().getOutcomeType().addAll(
        XmlLoader.splitStringToList(this.outcomeTypes, "\n"));
  }

  /**
   * Return the Iterator of List that contains Years
   * @return an Interator of BigInteger
   */
  public Iterator<BigInteger> getYearsIterator() {
    return this.collaboration.getYears().getYear().iterator();
  }

  /**
   * Get a String that represents Years.
   * 
   * @return a String that contain several names, separated by "\n".
   */
  public String getYears() {
    if (this.years == null) {
      this.years = XmlLoader.joinBigIntegerListToString(this.collaboration.getYears().getYear(),
          "\n");
    }
    return this.years;
  }

  /**
   * Set a String that represents Years.
   * 
   * @param years a String that contain several names, separated by "\n".
   */
  public void setYears(String years) {
    this.years = years;
    this.collaboration.setYears(new Years());
    this.collaboration.getYears().getYear().addAll(
        XmlLoader.splitStringToBigIntegerList(this.years, "\n"));
  }

  /**
   * Provides an iterator over the Collaborations to the page.
   * 
   * @return The organizations iterator.
   */
  public Iterator<Collaboration> getCollaborationsIterator() {
    return myIsern.getCollaborationList().iterator();
  }
  
  /**
   * Return a list of invalid referencer of organiztion within this colloboration.
   * @return a List of String.
   */
  public List<String> getInvalidReferenceInCollaboration() {
    return this.myIsern.getInvalidReference(this.collaboration);
  }
  
  /**
   * Updates the organization's information if the organization already exists in the list,
   * otherwise adds the collaboration to the list.
   * 
   * @return A Resolution indicating to display the organizationDisplayMessage.jsp page.
   */
  public Resolution save() {
    if (this.collaboration.getName() == null || this.collaboration.getName().length() == 0) {
      this.message = "Nothing is added.";
    }
    //Check if there is any invalid information
    else if (this.myIsern.semanticCheck(this.collaboration)) {
      //See if it is a new collaboration.
      if (this.myIsern.add(this.collaboration)) {
        this.message = " Thank you for entering Collaboration " + this.collaboration.getName();
      }
      else {
        this.message = "Collaboration " + this.collaboration.getName() + " has been updated.";
      }
    }
    else {
      //if has invalid information.
      this.message = "There are invalid information within your input.\n";
      String invalidYears = "";
      for (BigInteger year : this.collaboration.getYears().getYear()) {
        if (year.intValue() > 2010 || year.intValue() < 1990) {
          this.collaboration.getYears().getYear().remove(year);
          invalidYears += year.toString() + ", ";
        }
      }
      if (invalidYears.length() > 0) {
        this.message += "Invalid years " + invalidYears + "are removed.";
      }
      this.myIsern.add(this.collaboration);
      return new ForwardResolution("/collaborationError.jsp");
    }
    return new ForwardResolution("/collaborationsList.jsp");
  }

  /**
   * Finds the collaboration to edit if the collaboration already exists.
   * 
   * @return A Resolution indicating to display the organizationEdit.jsp page.
   */
  public Resolution edit() {
    this.collaboration = this.myIsern.getCollaboration(this.getName());
    if (this.collaboration == null) {
      this.collaboration = new Collaboration();
      this.collaboration.setCollaboratingOrganizations(new CollaboratingOrganizations());
      this.collaboration.setCollaborationTypes(new CollaborationTypes());
      this.collaboration.setYears(new Years());
      this.collaboration.setOutcomeTypes(new OutcomeTypes());
    }
    return new ForwardResolution("/collaborationEdit.jsp");
  }

  /**
   * Finds the collaboration to display.
   * 
   * @return A Resolution indicating to display the collaborationView.jsp page.
   */
  public Resolution view() {
    if (this.myIsern.hasCollaboration(this.getName())) {
      this.collaboration = this.myIsern.getCollaboration(this.getName());
      return new ForwardResolution("/collaborationView.jsp");
    }
    else {
      return new ForwardResolution("/collaborationNotExist.jsp");
    }
  }

  /**
   * Deletes the collaboration specified by name.
   * 
   * @return A Resolution indicating to display the collaborationDisplayMessage.jsp page.
   */
  public Resolution delete() {
    if (this.myIsern.remove(this.getName())) {
      this.message = "Collaboration: " + this.getName() + "was successfully deleted";
    }
    else {
      this.message = "Collaboration: " + this.getName() + "not found. Maybe delete by other users";
    }
    return new ForwardResolution("/collaborationsList.jsp");
  }

  /**
   * Forwards the user to the collaborationsList.jsp page to view all researchers.
   * 
   * @return A Resolution indicating to redisplay the collaborationsList.jsp page.
   */
  @DefaultHandler
  public Resolution listCollaborations() {
    return new ForwardResolution("/collaborationsList.jsp");
  }
}
